﻿using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.ObjectModel;
using System.Linq;
using System.Collections.Generic;
using System;
using TFSUtils.Model;
using GalaSoft.MvvmLight.Views;
using GalaSoft.MvvmLight.Ioc;

namespace TFSUtils.ViewModel
{
    /// <summary>
    /// This class contains properties that the main View can data bind to.
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>    
    public class MainViewModel : ViewModelBase
    {           
        public RelayCommand ValidateUriCommand { get; private set; }
        public RelayCommand FindOrphanedWorkspaceCommand { get; private set; }
        public RelayCommand CleanWorkspaceCommand { get; private set; }
        public RelayCommand ShowCheckoutStatusCommand { get; private set; }
        public RelayCommand ShowWorkItemsInBuildCommand { get; private set; }

        // Store a local list of all registered commands to inform of updates
        private List<RelayCommand> _registeredCommands;

        private string _TFSUri;        
        private ObservableCollection<StatusItem> _status;
        private bool _working = false;
        private bool _isCurrentUriValid = false;

        private readonly IDataService _dataService;
        private readonly INavigationService _navigationService;

        public bool IsCurrentURIValid
        {
            get { return _isCurrentUriValid; }
            set
            {
                _isCurrentUriValid = value;
                RaisePropertyChanged();
                IsUriValidReevaluateCommands();
            }
        }

        /// <summary>
        /// TFS URI stores the path to the TFS server (e.g. https://mytfsserver.visualstudio.com/defaultcollection)
        /// </summary>        
        public string TFSUri
        {
            get
            {
                return _TFSUri;
            }

            set
            {
                if (_TFSUri == value)
                {
                    return;
                }

                _TFSUri = value;
                _isCurrentUriValid = false;
                RaisePropertyChanged("TFSUri");                
            }
        }

        private Queue<string> _tfsUriHistory;
        public Queue<string> TFSUriHistory
        {
            get
            {
                if (_tfsUriHistory == null) _tfsUriHistory = new Queue<string>(10);
                return _tfsUriHistory;
            }

            set
            {
                _tfsUriHistory = value;
                RaisePropertyChanged(() => TFSUriHistory);
            }
        }

        public bool Working
        {
            get
            {
                return _working;
            }

            set
            {
                if (_working == value)
                {
                    return;
                }

                _working = value;
                RaisePropertyChanged("Working");
            }
        }

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel(IDataService dataService, INavigationService navigationService)
        {
            SimpleIoc.Default.Register<TFSBasicData>();

            _navigationService = navigationService;            

            _dataService = dataService;
            _dataService.GetData(
                (item, error) =>
                {
                    if (error != null)
                    {
                        // Report error here
                        AddToStatus(error.Message, StatusType.Error);
                        return;
                    }

                    if (item != null)
                    {
                        TFSUri = item.URI;
                        TFSUriHistory = new Queue<string>(item.URIHistory);
                    }
                });
            
            ValidateUriCommand = RegisterNewCommand(ValidateUri, CanValidateUri);
            FindOrphanedWorkspaceCommand = RegisterNewCommand(FindOrphanedWorkspaces, () => IsCurrentURIValid);
            CleanWorkspaceCommand = RegisterNewCommand(CleanWorkspaces, () => IsCurrentURIValid);
            ShowCheckoutStatusCommand = RegisterNewCommand(GetCurrentCheckoutStatus, () => IsCurrentURIValid);
            ShowWorkItemsInBuildCommand = RegisterNewCommand(ShowWorkItemsInBuild, () => IsCurrentURIValid);
        }

        private RelayCommand RegisterNewCommand(Action onExecute, Func<bool> canExecute)
        {
            if (_registeredCommands == null)
            {
                _registeredCommands = new List<RelayCommand>();
            }

            RelayCommand newCommand = new RelayCommand(onExecute, canExecute);
            _registeredCommands.Add(newCommand);
            return newCommand;
        }

        private bool CanValidateUri()
        {
            return !IsCurrentURIValid;
        }
        private void ValidateUri()
        {                        
            var cn = new TFSUtilLibrary.Connection(TFSUri);
            IsCurrentURIValid = (cn.ConnectToTFS());
            
        }

        private void ShowWorkItemsInBuild()
        {
            SaveData();

            _navigationService.NavigateTo("BuildAnalysis");            

        }


        /// <summary>
        /// populate status with a list of currently checked-out files
        /// </summary>
        private void GetCurrentCheckoutStatus()
        {
            try
            {
                DateTime checkedoutDate = DateTime.Now;
                var results = TFSUtilLibrary.History.GetCheckedOutAt(TFSUri, checkedoutDate);
                
                AddToStatus(results.OrderBy(r => r.DateCheckedOut).Select(a => a.ToString()), StatusType.Information);
            }
            catch (Exception ex)
            {
                AddToStatus(ex.Message.ToString(), StatusType.Error);
            }
        }

        /// <summary>
        /// Call method to retrieve all workspaces that currently have no pending changes
        /// </summary>
        private void FindOrphanedWorkspaces()
        {
            try
            {
                var results = TFSUtilLibrary.CleanWorkspace.GetWorkspacesWithNoPendingChanges(TFSUri);
                AddToStatus(results, StatusType.Workspace);
            }
            catch (Exception ex)
            {
                AddToStatus(ex.Message.ToString(), StatusType.Error);
            }
        }

        private void CleanWorkspaces()
        {
            try
            {
                var results = TFSUtilLibrary.CleanWorkspace.RemoveWorkspaces(TFSUri, 
                    _status.Where(s => s.ItemType == StatusType.Workspace).Select(s => s.Description).ToList());

                AddToStatus(results, StatusType.Workspace);
            }
            catch (Exception ex)
            {
                AddToStatus(ex.Message.ToString(), StatusType.Error);
            }
        }

        #region Status

        public ObservableCollection<StatusItem> Status
        {
            get { return _status; }
            set
            {
                if (_status == value)
                {
                    return;
                }

                _status = value;
                RaisePropertyChanged("Status");
            }
        }        

        /// <summary>
        /// Add a single status with a specified type
        /// </summary>
        /// <param name="newStatus"></param>
        /// <param name="itemType"></param>
        protected void AddToStatus(string newStatus, StatusType itemType)
        {
            if (_status == null)
            {
                _status = new ObservableCollection<StatusItem>();                
            }
            StatusItem newStatusItem = new StatusItem()
            {
                DateStamp = DateTime.Now,
                Description = newStatus,
                ItemType = itemType
            };
            _status.Add(newStatusItem);

            RaisePropertyChanged("Status");
        }

        /// <summary>
        /// Take a list of strings and create a list of statuses
        /// </summary>
        /// <param name="newStatusList"></param>
        /// <param name="itemType"></param>
        protected void AddToStatus(IEnumerable<string> newStatusList, StatusType itemType)
        { 
            foreach (string stat in newStatusList)
            {
                AddToStatus(stat, itemType);
            }
        }

        protected void AddToStatus(IList<StatusItem> status)
        {
            if (_status == null)
            {
                _status = new ObservableCollection<StatusItem>(status);
            }
            else
            {
                _status = new ObservableCollection<StatusItem>(_status.Concat(status));
            }

            RaisePropertyChanged("Status");
        }

        #endregion        

        public override void Cleanup()
        {
            SaveData();

            base.Cleanup();
        }

        internal void SaveData()
        {
            TFSBasicData data = SimpleIoc.Default.GetInstance<TFSBasicData>();
            data.URI = TFSUri;
            data.URIHistory = TFSUriHistory.ToList();

            _dataService.SaveData(data);
        }

        private void IsUriValidReevaluateCommands()
        {
            foreach (var eachCommand in _registeredCommands)
            {
                eachCommand.RaiseCanExecuteChanged();
            }

        }
    }
}